
//
// 101203 - AH - Created.
//

package org.soekrat.engine.wheel.test.util;

import java.io.CharArrayWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;

import org.soekrat.engine.forest.Forest;
import org.soekrat.engine.io.SoekratXmlHandler;
import org.soekrat.engine.io.XmlHandler;
import org.soekrat.engine.visitor.TokenizedLine;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;

/**
 * <p>
 *   Parsing XML for testing 
 *   {@link Forest} retrieval strategies.
 * </p>
 * @author Arne Halvorsen (AH)
 * @author Laetitia Le Chatton (LLC) 
 */
public final class ForestSpokeXmlTestCases 
{
  private final List<ForestSpokeTestCase> m_cases=
    new ArrayList<ForestSpokeTestCase>();
  
  /**
   * <p>
   *   Constructor.
   * </p>
   * @param f Represents XML file to parse.
   * @throws IOException If fails.
   */
  ForestSpokeXmlTestCases(File testF, File forestF) throws IOException
  { 
    FileInputStream testFis=null;
    FileInputStream forestFis=null;
    try
    {
      if (testF!=null) testFis=new FileInputStream(testF);
      if (forestF!=null) forestFis=new FileInputStream(forestF);
      parse(testFis, forestFis);
    }
    finally
    {
      if (testFis!=null) try { testFis.close(); } catch (IOException _){}
      if (forestFis!=null) try { forestFis.close(); } catch (IOException _){}
    }
  }
  
  /**
   * <p>
   *   Constructor.
   * </p>
   * @param is Stream of XML to parse.
   * @throws IOException If fails.
   */
  ForestSpokeXmlTestCases(InputStream testIs, InputStream forestIs) 
    throws IOException { parse(testIs, forestIs); }
  
  // Invoked from constructors to do parsing.
  private void parse(InputStream testIs, InputStream forestIs) 
    throws IOException
  {
    SAXParserFactory factory=SAXParserFactory.newInstance();
    factory.setNamespaceAware(false);
    factory.setValidating(false);
    try
    {
      H h=new H();
      if (testIs!=null) factory.newSAXParser().parse(testIs, h);
      if (forestIs!=null) 
      {
        factory.newSAXParser().parse(forestIs, h);
        Forest forest=h.m_forest;
        
        for (ForestSpokeTestCase c : m_cases)
        {
          c.setForest(forest);
        }
      }
    }
    catch (ParserConfigurationException pcx){ throw new IOException(pcx); }
    catch (SAXException saxx){ throw new IOException(saxx); }
  }
  
  private final class H extends XmlHandler
  {
    private Locator m_loc=null;
    
    private final StringBuilder m_chars=new StringBuilder();
    
    private SoekratXmlHandler m_sxh=new SoekratXmlHandler();
    
    private ForestSpokeTestCase m_case=null;
    
    private Forest m_forest=null;
    
    @Override
    public void setDocumentLocator(Locator loc) 
    {
      m_loc=loc;
      m_sxh.setDocumentLocator(m_loc);
    }

    @Override
    public void startElement(String uri, String lName, String qName,
      Attributes attrs) throws SAXException 
    {
      String n=qName;
      
           if (n.equals("forest-test")) ;
      else if (n.equals("case"))        caseStart(attrs);
      else if (n.equals("keywords"))    keywordsStart(attrs);
      else if (m_sxh.handleElement(n))
      {
        m_sxh.startElement(uri, lName, qName, attrs);
      }
    }
    
    @Override
    public void characters(char[] ch, int start, int length)
      throws SAXException 
    {
      m_chars.append(ch, start, length);
    }

    @Override
    public void endElement(String uri, String lName, String qName)
      throws SAXException 
    {
      String n=qName;
      
      if (m_sxh.handleElement(qName)) m_sxh.endElement(uri, lName, qName);
      
           if (n.equals("forest"))   forestEnd();
      else if (n.equals("output"))   outputEnd();
      else if (n.equals("keywords")) keywordsEnd();
    }
    
    private void keywordsStart(Attributes attrs) throws SAXException
    { 
      m_chars.setLength(0);
    }
    
    private void keywordsEnd() throws SAXException
    {
      String s=m_chars.toString();
      s=(s==null) ? "" : s.trim();
      if (s.length()>0)
      {
        TokenizedLine keywords=new TokenizedLine();
        StringTokenizer st=new StringTokenizer(s, ", ");
        while (st.hasMoreTokens()) keywords.add(st.nextToken());
        m_case.setKeywords(keywords);
      }
    }
    
    private void caseStart(Attributes attrs) throws SAXException
    {
      String name=getMandatoryAttr("name", attrs);
      m_case=new ForestSpokeTestCase(name);
      m_cases.add(m_case);
    }
    
    private void forestEnd(){ m_forest=m_sxh.getForest(); }
    
    private void outputEnd()
    {
      Forest forest=m_sxh.getForest();
      
      m_case.setOutput(forest);
      forest.clear();
    }
    
  }
  
  /**
   * <p>
   *   Gets number of test cases.
   * </p>
   * @return Count.
   */
  public int size(){ return m_cases.size(); }
  
  public ForestSpokeTestCase getCase(int idx)
  {
    return m_cases.get(idx);
  }
  
  @Override
  public String toString() 
  {
    CharArrayWriter caw=new CharArrayWriter();
    PrintWriter pw=new PrintWriter(caw);
    
    for (ForestSpokeTestCase curr : m_cases) 
    {
      pw.println(curr);  
    }
    
    pw.flush();
    return caw.toString();
  }
  
  public static ForestSpokeXmlTestCases getCases()
  {
    try
    {
      return new ForestSpokeXmlTestCases(new File("./documents/tree.xml"), 
        new File("./documents/soekrat.xml"));
    }
    catch (IOException iox)
    {
      iox.printStackTrace();
      return null;
    }
  }
  
  public static void main(String[] args) 
  {
    ForestSpokeXmlTestCases cases=getCases();
    System.out.print(cases);
  }
  
}
